package cn.hicard.risk.io;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import cn.hicard.risk.entity.BdTradefileinfo;
import cn.hicard.util.AppConfig;
import cn.hicard.util.CardInfo;

/**
 * 传统POS的交易文件分析器
 * @author zhangy
 *
 */
public class PosTradeFileAnalyzer {
	
	/**
	 * 分析标准的传统POS交易文本的数据流
	 * @param inStream  交易文件文本的数据流
	 * @param area 交易的地区(注：每个文件内部的交易数据应为同一地区)
	 * @return 交易数据实体集合
	 * @throws IOException
	 * @throws AnalyzeException
	 */
	public List<BdTradefileinfo> analyze(InputStream inStream, String area) throws Exception {
		
		// 读入数据流
		BufferedReader bfReader = null;
		String coding = AppConfig.get("coding");//系统编码
		Reader in = new InputStreamReader(inStream, Charset.forName(coding));
		bfReader = new BufferedReader(in);
		
		
		List<BdTradefileinfo> list = new ArrayList<BdTradefileinfo>();
		int itemLength = 11;
		String line = null;
		try {
			while((line = bfReader.readLine()) != null){
				// 检查是否为空行
				line = line.trim();
				if(line.length() == 0){
					continue;
				}
				
				// 替换为单分割符
				line = line.replaceAll("\t{2,}", "\t");
				// 分割数据
				String[] split = line.split("\t");
				// 检查数据项是否齐全
				if(split.length != itemLength){
					// 抛出异常前，关闭数据流，以防占用
					bfReader.close();
					throw new AnalyzeException(
							"交易的数据格式错误，正确的数据项长度为" + itemLength
							+ "，而读取到的数据项长度为" + split.length 
							+ "，数据内容：" + line);					
				}
				BdTradefileinfo trade = new BdTradefileinfo();
				/*
				 * 2012年10月22日，由于清算业务变更，传统POS数据中，银联不再提供“银联商户名”，因此使用汇卡商户名代替
				 * 其它未使用，但已经没有数据的字段：
				 * 发卡银行名称、交易费用、结算金额、流水号、渠道
				 */
				
				trade.setWpmerchno(split[0]);							//[0]汇卡商户号
				trade.setMerchname(split[1]);							//[1]“银联商户名”，用[汇卡商户名]顶替
				trade.setMerchno(split[2]);								//[2]银联商户号，查询的依据				
				trade.setTermno(split[3]);								//[3]银联终端号，查询的依据
				trade.setTransdate(split[4]);							//[4]交易日期
				trade.setTranstime(split[5].substring(4,14));			//[5]交易时间，截取出"MMddHHmmss"部分
				trade.setCardno(split[6]);								//[6]交易账号
				trade.setTransmoney(convertFormat(split[7]));			//[7]交易金额
				trade.setTranstypename(split[8]);						//[8]类型
				trade.setSysno(split[9]);								//[9]系统参考号
				trade.setCardtype(CardInfo.getCardtype(split[6]));		// 卡属性：信用卡OR借记卡				
				trade.setCardtypename(CardInfo.getCardtypeName(trade.getCardtype()));// 设定卡属性名称
				trade.setArea(area);									// 地区
				trade.setCallflag(split[10]);                           // 调单业务标志位
				
				list.add(trade);
			}
		} catch (Exception e) {
			throw e;
		} finally {
			bfReader.close();
		}
		return list;
	}
	
	private DecimalFormat format = new DecimalFormat("0.00"); 
	/**
	 * 将字符串以“分”为单位的金额转为以元为单位两位上数的金额字符串<br/>
	 * 针对2012年10月的变动
	 * @param money
	 * @return
	 */
	private String convertFormat(String money){		
		return format.format(Double.valueOf(money) / 100);
	}
	
	/**
	 * 分析标准的传统POS交易文件的数据
	 * @param file 交易文件
	 * @param area 交易的地区(注：每个文件内部的交易数据应为同一地区)
	 * @return 交易数据实体集合
	 * @throws IOException
	 * @throws AnalyzeException 
	 */
	public List<BdTradefileinfo> analyze(File file, String area) throws Exception{
		return analyze(new FileInputStream(file), area);
	}

	/**
	 * 分析标准的传统POS交易文件的数据，交易所在的地区由系统跟据文件名称自动分析
	 * @param file 交易文件
	 * @return 交易数据实体集合
	 * @throws IOException
	 * @throws AnalyzeException
	 */
	public List<BdTradefileinfo> analyze(File file) throws Exception{
		String area = judgeArea(file.getName());
		return analyze(file, area);
	}
	
	/**
	 * 跟据交易文件的名称判断该交易文件所属的地区
	 * @param name
	 * @return
	 * @throws AnalyzeException 
	 */
	private String judgeArea(String name) throws AnalyzeException {
		String area = null;
		if(name.startsWith("NB")){
			area = "宁波";
		}else if(name.startsWith("HZ")){
			area = "杭州";
		}else{
			throw new AnalyzeException("无法从文件名：" + name + " 中解析出地区");
		}		
		return area;
	}
}
